import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'dart:typed_data';
import 'package:douyin_live_app/services/js_signature_generator.dart';
import 'package:web_socket_channel/io.dart';
import 'package:web_socket_channel/web_socket_channel.dart';
import 'package:crypto/crypto.dart';
import 'package:http/http.dart' as http;

// 导入 protobuf 生成的代码和解析器
import '../protos/douyin.pb.dart' as douyin;
import 'douyin_message_parser.dart';

class DouyinWebSocketService {
  static final DouyinWebSocketService _instance = DouyinWebSocketService._internal();
  factory DouyinWebSocketService() => _instance;
  DouyinWebSocketService._internal();

  WebSocketChannel? _channel;
  bool _isConnected = false;
  String? _currentRoomId;
  String? _ttwid;
  Timer? _heartbeatTimer; // 心跳定时器
  bool _heartbeatRunning = false; // 心跳运行状态
  final String _userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36';
  
  // 连接状态回调
  Function(bool)? onConnectionChanged;
  Function(Map<String, dynamic>)? onMessageReceived; // 改为 protobuf 消息类型
  Function(String)? onError;
  Function(douyin.Message)? onRawMessageReceived;

  Future<bool> connect(String liveId) async {
    try {
      _currentRoomId = liveId;
      
      // 1. 获取TTWID
      _ttwid = await _getTtwid(liveId);
      if (_ttwid == null) {
        onError?.call('无法获取TTWID');
        return false;
      }

      // 2. 获取真实roomId
      final String realRoomId = await _getRealRoomId(liveId);
      if (realRoomId.isEmpty) {
        onError?.call('无法获取直播间信息');
        return false;
      }

      // 3. 获取WebSocket连接URL
      final String wsUrl = await _getWebSocketUrl(realRoomId);
      if (wsUrl.isEmpty) {
        onError?.call('无法获取WebSocket连接信息');
        return false;
      }

      // 4. 连接WebSocket
      try {
        print('开始 WebSocket 连接...');
        
        // 使用 IOWebSocketChannel 的静态方法
        _channel = IOWebSocketChannel.connect(
          Uri.parse(wsUrl),
          headers: {
            'User-Agent': _userAgent,
            'Cookie': 'ttwid=$_ttwid',
          },
        );
        // 设置解析器的 WebSocket 实例用于发送 ACK
        DouyinMessageParser.setWebSocket(_channel!);

        print('WebSocket 连接成功');
        
        _channel!.stream.listen(
          _handleMessage,
          onError: (error) {
            print('WebSocket流错误: $error');
            _isConnected = false;
            _stopHeartbeat(); // 停止心跳
            onError?.call('WebSocket错误: $error');
            onConnectionChanged?.call(false);
          },
          onDone: () {
            print('WebSocket连接关闭');
            _isConnected = false;
            _stopHeartbeat(); // 停止心跳
            onConnectionChanged?.call(false);
          },
        );

        _isConnected = true;
        onConnectionChanged?.call(true);
        
        // 启动心跳
        _startHeartbeat();

        return true;
      } catch (e) {
        print('WebSocket连接异常: $e');
        onError?.call('WebSocket连接失败: $e');
        return false;
      }
    } catch (e) {
      onError?.call('连接失败: $e');
      return false;
    }
  }

  void disconnect() {
    _isConnected = false;
    _stopHeartbeat();
    _channel?.sink.close();
    onConnectionChanged?.call(false);
  }

  bool get isConnected => _isConnected;
  // 启动心跳
  void _startHeartbeat() {
    _heartbeatRunning = true;
    print('启动心跳包...');
    
    _heartbeatTimer = Timer.periodic(Duration(seconds: 15), (timer) {
      if (!_heartbeatRunning || !_isConnected || _channel == null) {
        print('心跳包: WebSocket 未连接，停止发送心跳包');
        _stopHeartbeat();
        return;
      }
      
      try {
        final heartbeat = DouyinMessageParser.buildHeartbeat();
        if (heartbeat.isNotEmpty) {
          _channel!.sink.add(heartbeat);
        }
      } catch (e) {
        print('心跳包发送错误: $e');
        _stopHeartbeat();
      }
    });
  }

  // 停止心跳
  void _stopHeartbeat() {
    _heartbeatRunning = false;
    _heartbeatTimer?.cancel();
    _heartbeatTimer = null;
    print('停止心跳包');
  }

  Future<String?> _getTtwid(String liveId) async {
    try {
      final response = await http.get(
        Uri.parse('https://live.douyin.com/$liveId'),
        headers: {'User-Agent': _userAgent},
      );
      print('response: ${response.statusCode}');
      if (response.statusCode == 200) {
        final cookieHeader = response.headers['set-cookie'];
        if (cookieHeader != null) {
          final ttwidMatch = RegExp(r'ttwid=([^;]+)').firstMatch(cookieHeader);
          if (ttwidMatch != null) {
            return ttwidMatch.group(1);
          }
        }
      }
      return null;
    } catch (e) {
      print('获取TTWID错误: $e');
      return null;
    }
  }

  Future<String> _getRealRoomId(String liveId) async {
    try {
      final msToken = _generateMsToken();
      final response = await http.get(
        Uri.parse('https://live.douyin.com/$liveId'),
        headers: {
          'User-Agent': _userAgent,
          'Cookie': 'ttwid=$_ttwid; msToken=$msToken; __ac_nonce=0123407cc00a9e438deb4',
        },
      );

      if (response.statusCode == 200) {
        final RegExp roomIdRegExp = RegExp(r'roomId\\?"\s*:\s*\\?"(\d+)\\"');
        final Match? match = roomIdRegExp.firstMatch(response.body);
        
        if (match != null) {
          return match.group(1)!;
        }
      }
      return liveId;
    } catch (e) {
      print('获取真实RoomId错误: $e');
      return liveId;
    }
  }

  String _generateMsToken({int length = 107}) {
    const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=_';
    final random = Random();
    return String.fromCharCodes(
      Iterable.generate(
        length, 
        (_) => chars.codeUnitAt(random.nextInt(chars.length))
      )
    );
  }

  Future<String> _getWebSocketUrl(String roomId) async {
    // 使用正确的参数构建方式
    final parameters = {
      'app_name': 'douyin_web',
      'version_code': '180800',
      'webcast_sdk_version': '1.0.14-beta.0',
      'update_version_code': '1.0.14-beta.0',
      'compress': 'gzip',
      'device_platform': 'web',
      'cookie_enabled': 'true',
      'screen_width': '1536',
      'screen_height': '864',
      'browser_language': 'zh-CN',
      'browser_platform': 'Win32',
      'browser_name': 'Mozilla',
      'browser_version': '5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
      'browser_online': 'true',
      'tz_name': 'Asia/Shanghai',
      'internal_ext': 'internal_src:dim|wss_push_room_id:$roomId|wss_push_did:7319483754668557238|first_req_ms:${DateTime.now().millisecondsSinceEpoch}|fetch_time:${DateTime.now().millisecondsSinceEpoch + 100}|seq:1|wss_info:0-${DateTime.now().millisecondsSinceEpoch + 100}-0-0|wrds_v:7392094459690748497',
      'host': 'https://live.douyin.com',
      'aid': '6383',
      'live_id': '1',
      'did_rule': '3',
      'endpoint': 'live_pc',
      'support_wrds': '1',
      'user_unique_id': '7319483754668557238',
      'im_path': '/webcast/im/fetch/',
      'identity': 'audience',
      'room_id': roomId,
      'heartbeatDuration': '0',
    };

    // 使用 Uri 类正确构建 URL
    final uri = Uri(
      scheme: 'wss',
      host: 'webcast5-ws-web-hl.douyin.com',
      port: 443, // 显式指定端口
      path: '/webcast/im/push/v2/',
      queryParameters: parameters,
    );

    final baseUrl = uri.toString();
    
    final signature = await _generateSignature(baseUrl);
    if (signature.isEmpty) {
      return '';
    }
    
    // 手动添加签名参数，避免再次编码
    final finalUrl = '$baseUrl&signature=$signature';

    return finalUrl;
  }

  Future<String> _generateSignature(String wssUrl) async {
    try {
      await JsSignatureGenerator.initialize();
      
      final uri = Uri.parse(wssUrl);
      final params = uri.queryParameters;
      
      const paramOrder = [
        'live_id', 'aid', 'version_code', 'webcast_sdk_version',
        'room_id', 'sub_room_id', 'sub_channel_id', 'did_rule',
        'user_unique_id', 'device_platform', 'device_type', 'ac',
        'identity'
      ];
      
      final paramString = paramOrder
          .map((key) => '$key=${params[key] ?? ''}')
          .join(',');
      
      final md5Hash = md5.convert(utf8.encode(paramString)).toString();
      
      // 使用 JavaScript 引擎生成签名
      final signature = JsSignatureGenerator.generateSignature(md5Hash);
      
      if (signature == null) {
        throw Exception('JavaScript 签名生成失败');
      }
      
      return signature;
    } catch (e) {
      print('生成签名错误: $e');
      return '';
    }
  }

  void _handleMessage(dynamic message) {
    try {
      if (message is List<int>) {
        _processBinaryMessage(Uint8List.fromList(message));
      } else if (message is String) {
        _processTextMessage(message);
      }
    } catch (e) {
      print('消息处理错误: $e');
    }
  }

  void _processBinaryMessage(Uint8List data) {
    try {
      // 使用 protobuf 解析器解析消息
      final messages = DouyinMessageParser.parseWebSocketMessage(data);
      
      // 处理所有解析出的消息
      for (final message in messages) {
        
        // 回调原始 protobuf 消息（如果需要）
        onRawMessageReceived?.call(message);
        
        // 转换为界面可用的格式并回调
        final uiMessage = DouyinMessageParser.convertToUIMessage(message);
        if (uiMessage != null) {
          onMessageReceived?.call(uiMessage);
        }
        
        // 根据消息类型进行具体处理（控制台输出）
        _handleSpecificMessage(message);
      }
      
    } catch (e) {
      print('处理二进制消息错误: $e');
      print('错误堆栈: ${e.toString()}');
    }
  }

  void _processTextMessage(String message) {
    try {
      final data = json.decode(message);
      print('收到文本消息: $data');
    } catch (e) {
      print('处理文本消息错误: $e');
    }
  }

  void _handleSpecificMessage(douyin.Message message) {
    try {
      switch (message.method) {
        case 'WebcastChatMessage':
          _handleChatMessage(message);
          break;

        default:
          break;
      }
    } catch (e) {
      print('处理特定消息 ${message.method} 错误: $e');
    }
  }

  void _handleChatMessage(douyin.Message message) {
    try {
      final chatMessage = douyin.ChatMessage.fromBuffer(message.payload);
      final user = chatMessage.user;
 
    } catch (e) {
      print('解析聊天消息错误: $e');
    }
  }

  // 发送消息的方法（如果需要）
  void sendMessage(Uint8List data) {
    if (_isConnected && _channel != null) {
      _channel!.sink.add(data);
    }
  }
}